package com.fengcheng.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class HdfsUtil {
    @Value("${hdfs.path}")
    private String path;
    @Value("${hdfs.username}")
    private String username;

    private static String hdfsPath;
    private static String hdfsName;
    private static final int bufferSize =   1024 * 1024 * 64;

    /*
     * @author 枫城
     * @createTime 2022/7/6 8:06
     * @desc 获取 hdfs配置信息
     */
    private static Configuration getConfiguration(){
        final Configuration conf = new Configuration();
        conf.set("fs.defaultFS", hdfsPath);
        return conf;
    }

    /*
     * @author 枫城
     * @createTime 2022/7/6 8:08
     * @desc 获取hdfs 文件系统
     */
    private static   FileSystem getFileSystem() throws Exception{
        FileSystem fileSystem= FileSystem.get(new URI(hdfsPath), getConfiguration(), hdfsName );
        return fileSystem;
    }

    /*
     * @author 枫城
     * @createTime 2022/7/10 11:32
     * @desc 通过路径查询文件路径
     */
    public static List<Map<String, Object>> getPathInfo(String path) throws Exception {
        final List<Map<String, Object>> list = new ArrayList<>();
        FileSystem fs =   getFileSystem();
        final Path newPath = new Path(path);
        final FileStatus[] fileStatuses = fs.listStatus(newPath);
        if (null != fileStatuses && fileStatuses.length>0){
            for (FileStatus status : fileStatuses) {
                final HashMap<String, Object> map = new HashMap<>();
                log.info("filePath : {}",status.getPath());
                // 获取到尾缀，判断文件类型 0：文件夹； 1：图片；2：文档； 3：未知
                String[] file =  status.getPath().toString().split("/");
                if (status.isDirectory()){
                    map.put("type",0);
                }else {
                    String[] t = status.getPath().toString().split("\\.");
                    String fileType = t[t.length-1];
                    log.info("type:{}",fileType);
                    if (fileType.equals("jpg") || fileType.equals("png")){
                        map.put("type",1);
                    }else if (fileType.equals("txt")||fileType.equals("docx")){
                        map.put("type",2);
                    }else {
                        map.put("type",3);
                    }
                }
                map.put("file",file[file.length-1]);
                log.info("信息：{}",map);
                list.add(map);
            }

            return list;
        }else {
            return null;
        }
    }

    /*
     * @author 枫城
     * @createTime 2022/7/6 8:12
     * @desc 创建空文件夹
     */
    public static boolean mkdir(String path) throws Exception {
        if (StringUtils.isEmpty(path)){
            log.info("信息： 参数为空！");
            return false;
        }
        if (existFileSystem(path)) {
            log.info("信息： 路径已经存在！");
            return true;
        }

        FileSystem fs = getFileSystem();
        final Path srcPath = new Path(path);
        log.info("信息： {} 已经创建成功！", srcPath);
        fs.mkdirs(srcPath);
        fs.close();
        return true;
    }

    /*
     * @author 枫城
     * @createTime 2022/7/6 8:16
     * @desc 判断文件是否存在
     */
    public static boolean existFileSystem(String path) throws Exception {
        if (StringUtils.isEmpty(path)){
            log.info("信息： 参数为空！");
            return false;
        }
        FileSystem fs =  getFileSystem();
        final Path srcPath = new Path(path);
        return fs.exists(srcPath);
    }

    /*
     * @author 枫城
     * @createTime 2022/7/6 9:01
     * @desc 上传文件
     */
    public static int uploadFile(MultipartFile fileStream, String uploadPath) throws Exception {
        if (StringUtils.isEmpty(uploadPath)){
            log.info("参数不完全！");
            return -1;
        }
        if (existFileSystem(uploadPath)){
            log.info("该文件已经存在！");
            return 1;
        }
        FileSystem fs = getFileSystem();
        final Path uploadHdfsPath = new Path(uploadPath);

        log.info("写入路径：{}",uploadHdfsPath);
        FSDataOutputStream fsDataOutputStream = fs.create(uploadHdfsPath);
        byte[] out = fileStream.getBytes();
        fsDataOutputStream.write(out);
        log.info("文件上传成功！");
        fs.close();
        return 1;
    }

    /**
     * 下载文件
     * @param upDownPath
     * @param path
     * @throws Exception
     */
    public static void upDownFile(String upDownPath, String path) throws Exception {
        if (StringUtils.isEmpty(upDownPath) || StringUtils.isEmpty(path)){
            log.info("参数不完全！");
            return;
        }
        FileSystem fs = getFileSystem();
        try {
            FileStatus[] fileStatuses = fs.listStatus(new Path(upDownPath));
            for (int i = 0; i<fileStatuses.length; i++){
                FileStatus fileStatus = fileStatuses[i];
                FSDataInputStream is = fs.open(new Path(String.valueOf(fileStatus.getPath())));
                String[] file =  fileStatus.getPath().toString().split("/");
                String fileNmae = file[file.length-1];
                FileOutputStream os = new FileOutputStream(new File(path) +"/"+fileNmae);
                IOUtils.copyBytes(is, os, 2048);
                is.close();
                os.close();
            }

        fs.close();
    } catch (
    IOException e) {
        e.printStackTrace();
    }}

    /*
     * @author 枫城
     * @createTime 2022/7/11 18:33
     * @desc 删除文件
     */
    public static boolean deleteFile(String path) throws Exception {
        if (StringUtils.isEmpty(path)) {
            return false;
        }
        if (!existFileSystem(path)) {
            return false;

        }
        FileSystem fs = getFileSystem();
        Path srcPath = new Path(path);
        boolean isOk = fs.deleteOnExit(srcPath);
        log.info("deleteFile is success!");
        fs.close();
        return isOk;
    }

    /**
     * 重命名文件
     * @param oldName
     * @param newName
     * @return
     * @throws Exception
     */


    public static Boolean reName(String oldName, String newName) throws Exception {
        if (StringUtils.isEmpty(oldName) || StringUtils.isEmpty(newName)){
            log.info("信息：参数不完整！");
            return false;
        }

        FileSystem fs = getFileSystem();

        Path oldPath = new Path(oldName);
        Path newPath = new Path(newName);
        try {
            fs.rename(oldPath,newPath);
            fs.close();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 移动文件
     * @param oldPath
     * @param newPath
     * @return
     * @throws Exception
     */
    public static Boolean moveFile(String oldPath, String newPath) throws Exception {
        if (StringUtils.isEmpty(oldPath) || StringUtils.isEmpty(newPath)){
            log.info("信息：参数不完整！");
            return false;
        }
        FileSystem fs = getFileSystem();

        Path oP = new Path(oldPath);
        Path nP = new Path(newPath);
        try {

            fs.moveToLocalFile(oP,nP);
            fs.close();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }

    }





    @PostConstruct
    public void getPath(){
        hdfsPath = this.path;
    }

    @PostConstruct
    public void getName(){
        hdfsName = this.username;
    }

    public static String getHdfsPath() {
        return hdfsPath;
    }

    public String getUsername() {
        return username;
    }

}
